﻿Public Class CS324TextBox
		'Function Declarations
		'Private Functions
		
		'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The clickstream exists
    'Post-Condition: The clickstream has nIputs more inputs, represented by
    '		the array pInputs, where pInputs is of size cbSize
    'Functionality: The inputs stored in pInputs are placed into the clickstream
    Private Declare Function SendInput Lib "user32.dll" ( _
     ByVal nInputs As Integer, ByRef pInputs As INPUT_TYPE, _
     ByVal cbSize As Integer) As Integer
     
     'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: None
		'Post-Condition: A caret has been created.
		'Functionality: Create a caret.
    Private Declare Function CreateCaret Lib "user32" (ByVal hWnd As IntPtr, _
     ByVal hBitmap As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer) As Boolean

		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: the a caret exists.
		'Post-Condition: The caret is shown
		'Functionality: Show the caret.
    Private Declare Function ShowCaret Lib "user32" (ByVal hWnd As IntPtr) _
     As Boolean

		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: A caret exists and is being shown.
		'Post-Condition: The caret is hidden.
		'Functionality: Hide the caret.
    Private Declare Function HideCaret Lib "user32" (ByVal hwnd As IntPtr) As Boolean

		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: A caret exists.
		'Post-Condition: There is no caret.
		'Functionality: Destroy the caret.
    Private Declare Function DestroyCaret Lib "user32" () As Boolean

		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: None
		'Post-Condition: The state of the key vKey is known.
		'Functionality: Find out if vKey is up or down.
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
		
		
		
		'Structure Declarations
		'Private Structures
		
		'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s):  N/A
    'Functionality: A structure used to represent system input
    Private Structure INPUT_TYPE
				
				'The type of input
		    Public dwType As Integer
		    
		    'The information about the mouse input
		    Public xi As MOUSEINPUT
    End Structure

    'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Functionality: A structure used to represent mouse events
    Private Structure MOUSEINPUT
       
				'Change in the cursors x position
		    Public dx As Integer
		    
		    'Change in the cursors y position
		    Public dy As Integer
		    
		    'Not used, just set to 0
		    Public mouseData As Integer
		    
		    'What kind of action is occurring
		    Public dwFlags As Integer
		    
		    'Not used, just set to 0
		    Public dwtime As Integer
		    
		    'Not used, just set to 0
		    Public dwExtraInfo As Integer
    End Structure
		
		
		
		'Event Declarations
		
    'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: A color change has occured
    'Post-Condition: users of the textbox get a color change event
    'Functionality: An event to raise.
    Public Event colorChanged(ByRef sender As Object, ByVal newColor As Color)

    Public Shadows Event textChanged(ByRef Sender As Object, ByVal e As System.EventArgs)
    
		
    'Property Declarations
		
    'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A 
    'Functionality: Get or set the character set that the textbox uses.
    Public Property charSet() As String
    		
        'What happens when getting the property
        Get
        		
            'If the charset val equls ALPHA_NUM then return the string "alphanum"
            If charSetVal = ALPHA_NUM Then
                Return "alphanum"
                
            'If the charset val equals ALPHA then return the string "alpha"
            ElseIf charSetVal = ALPHA Then
                Return "alpha"
                
            'If the charset val equals NUM then return the string "num"
            ElseIf charSetVal = NUM Then
                Return "num"
            End If
        End Get
        
        'What happens when setting the propery
        Set(ByVal value As String)
        		
        		'If the user sets the property to "alphanum" then set the charsetVal
        		'		to ALPHA_NUM
            If value.ToLower = "alphanum" Then
                charSetVal = ALPHA_NUM
                
            'If the user sets the property to "alpha" then set the charsetVal
        		'		to ALPHA
            ElseIf value.ToLower = "alpha" Then
                charSetVal = ALPHA
                
            'If the user sets the property to "num" then set the charsetVal
        		'		to ALPHA
            ElseIf value.ToLower = "num" Then
                charSetVal = NUM
            End If
        End Set
    End Property

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Functionality: Get or set the ability for the textbox to have multiple
		'		lines.
    Public Property multiline() As Boolean
    		
    		'What happens when getting the property
        Get
        		
        		'Return the multiline value for the textbox on this control
            Return TextBox1.Multiline
        End Get
        
        'What happens when setting the propery
        Set(ByVal value As Boolean)
        
        		'Set the multiline value for the textbox on this control to what
        		'		the user passes into the property
            TextBox1.Multiline = value
        End Set
    End Property

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A 
		'Functionality: Get or set the color of the text
    Public Property textColor() As System.Drawing.Color
    		
    		'What happens when getting the property
        Get
        	
        		'Return the text color of the textbox on this control
            Return TextBox1.ForeColor
        End Get
        
        'What happens when setting the propery
        Set(ByVal value As System.Drawing.Color)
        
        		'Set the text color of the textbox on this control to the color that
        		'		the user insrets into this propery
            TextBox1.ForeColor = value
        End Set
    End Property

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A 
		'Functionality: Get or set the text in the textbox
    Public Property displayText() As String
    		
    		'What happens when getting the property
        Get
        		'Get the text in the textbox on the control
            Return TextBox1.Text
        End Get
        
        'What happens when setting the propery
        Set(ByVal value As String)
        		'Set the text in the textbox on the control to the string the user
        		'		inserts into the property.
            TextBox1.Text = value
        End Set
    End Property

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A 
		'Functionality: Get or set the control that the focus will pass to when
		'		leaving the textbox.
    Public Property switchFocus() As Control
    		'What happens when getting the property
        Get
        		'Return the control that the focus switches towhen leaving
        		'the component
            Return switchTo
        End Get
        
        'What happens when setting the propery
        Set(ByVal value As Control)
        		'Set the switchTo object to what the user passes into the property.
            switchTo = value
        End Set
    End Property
		
		
		'Global Variables
		'Constant Private
		
		'Input types for the INPUT_TYPE structure
    'Module: Textbox Control
    Private Const INPUT_MOUSE = 0
    Private Const INPUT_KEYBOARD = 1
    Private Const INPUT_HARDWARE = 2

    'Key sates for ProcessCmdKey and ProcessKeyPreview
    'Module: Textbox Control
    Private Const WM_KEYDOWN As Integer = 256
    Private Const WM_SYSKEYDOWN As Integer = 260
    Private Const WM_KEYUP As Integer = 257
    Private Const WM_SYSKEYUP As Integer = 261

    'numerical representations of mouse events used by the INPUT_TYPE strructure
    'Module: Textbox Control
    Private Const MOUSE_MOVE = &H1
    Private Const MOUSE_LEFTDOWN = &H2
    Private Const MOUSE_LEFTUP = &H4
    
    'State variables for the charSet property representing which set of
		'		characters to use for the textbox
    Private Const ALPHA_NUM = 1
    Private Const ALPHA = 2
    Private Const NUM = 3
    
    'The maximum length of the textbox
    Const MAX_CHARS As Integer = 32767
		
		'State Variables
		
		'The maximum number of possible characters, the length of the chars array
    Dim MAX_CHARS_INDEX As Integer

		'An array of all possible characters that could be in the textbox.
    Dim chars() As Char
    
    'the Index of the charsArray
    Dim charsIndex As Integer = 0
    
    'An array that represents the text that is in the textbox.  It stores
    '		integers that correspond to characters in the chars array
    Dim textRepresentation(0) As Integer

		'The index of the textRepresentation array
    Dim boxIndex As Integer = 0
    
    'A flag representing if the enter key is down
    Dim enterKeyDown As Boolean = False
    
    'A flag representing if an arrow key was pressed with the enter key
    Dim arrowsPressedWithEnter As Boolean = False
    
    'a flag representing if the mouse button is released
    Dim mouseReleased As Boolean
    
    'A flag representing if the user is highlighting to the right
    Dim highlightRight As Boolean
        
    'The control to switch focus to in order to leave the textbox
    Dim switchTo As Control
	
		'The state of the textbox as to which characters to use
    Dim charSetVal As Integer = ALPHA_NUM
    
    
		
	'Function Definitions
    'Event Handlers

    'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The control has not been loaded.
    'Post-Condition: The control is loaded and set up.
    'Functionality: Set up the control when it loads.
    Private Sub TextBox1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
        'Set the mouseReleased to true when loading the textbox and make sure
        '		it is true by calling the keyMouseUp function
        mouseReleased = True
        keyMouseUp()

				'Set the valid characters for this textbox based on the charSetVal
				'		variable and the textboxes multiline property.
        If charSetVal = ALPHA_NUM Then
            
            If TextBox1.Multiline Then
                chars = New Char() {" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ",", "?", Chr(13) + Chr(10)}
            Else
                chars = New Char() {" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", ",", "?"}
            End If
            
        ElseIf charSetVal = ALPHA Then
            
            If TextBox1.Multiline Then
                chars = New Char() {" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ".", ",", "?", Chr(13) + Chr(10)}
            Else
                chars = New Char() {" ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", ".", ",", "?"}
            End If
            
        ElseIf charSetVal = NUM Then
            
            If TextBox1.Multiline Then
                chars = New Char() {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", Chr(13) + Chr(10)}
            Else
                chars = New Char() {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."}
            End If
            
        End If
        
        'Set the maximum number of characters in the chars array
        MAX_CHARS_INDEX = chars.Length

        'If the textbox loads with text in it, the text needs to be loaded
        'into the textRepresentation array and properly handled
        BoxToArray()
    End Sub
		

	'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The size of the control has changed.
    'Post-Condition: The size of the textbox on the control is changed to the
    '		same size as the control.
    'Functionality: Resize the textbox to the same size as the control.
    Private Sub CS324TextBox_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.SizeChanged
        'Set the textbox to the same size as the control
        TextBox1.Size = New Size(Me.Size)
    End Sub
    
    'Developer Name: Jason Lyle
	'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The mouse pressed down on the textbox.
    'Post-Condition: A mouse up event is sent into the clickstream and the
    'mouseReleased flag keeps track of if the mouse is "still down".
    'Functionality: Handle the mouse clicking on the textbox.
    Private Sub TextBox1_MouseDown(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.MouseDown
        'The the position of the caret
        boxIndex = TextBox1.SelectionStart - 1

				'If the position is less than 0, set it to 0
        If boxIndex < 0 Then
            boxIndex = 0
        End If

				'Get the index of the letter that the textbox is on
        charsIndex = textRepresentation(boxIndex)
        
        'Set the state variable mouseReleased
        mouseReleased = (GetAsyncKeyState(Keys.LButton) = 0)
        
        'Ensure that the mouse is up by calling keyMouseUp.  The mousehandling
        'Done by the textbox uses boolean flags rather than mouse states.
        keyMouseUp()
    End Sub
    
    'Developer Name: Jason Lyle
	'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: the textbox did not have focus.
    'Post-Condition: The textbox has focus and is updated appropriately.
    'Functionality: Update the textbox when it gets focus.
    Private Sub TextBox1_Focus(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.GotFocus
        
        'If the textbox is empty, then call the clear function to set up the
        '		variables correctly for a empty textbox
        If TextBox1.Text = "" Then
            Clear()
        'Else, get the index of th letter that the caret is on
        Else
            charsIndex = textRepresentation(boxIndex)
        End If

				'The caret must be created everytime the textbox gets focus, because
				'		windows perpetually destroys and recreates the caret.
        CreateCaret(TextBox1.Handle, IntPtr.Zero, -7, FontHeight)
        
        'If nothing is selected, show the caret.
        If TextBox1.SelectionLength = 0 Then
            ShowCaret(TextBox1.Handle)
        End If

        'First, ensure that any text entered into the textbox is saved into the internal representation
        BoxToArray()
        'Then make sure that it is displayed correctly
        arrayToBox()
    End Sub

	'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The textbox had focus
    'Post-Condition: The textbox does not have focus and is set up to clear if
    '		just spances, or trims any trailing white space.
    'Functionality: Update the textbox when it loses focus.
    Private Sub TextBox1_Unfocus(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.LostFocus
        'Destroy the caret since we dont know if another CS324 textbox will be
        '		accessed after this
        DestroyCaret()

        'If the text box is just spaces then treat it as
        'clear it so it is an empty box.
        Dim encoding As Integer = 0
        Dim arraySize As Integer = textRepresentation.Length - 1
        For index As Integer = 0 To arraySize
            encoding += textRepresentation(index)
        Next
        
        'If encoding is 0, then there are not characters in the box
        If encoding = 0 Then
            TextBox1.Clear()
            ReDim textRepresentation(0)
            boxIndex = 0
        End If

        'Trim white space on the right end.
        For index As Integer = textRepresentation.Length - 1 To 1 Step -1
            
            'If the far right is a space, shorten the length of the 
            '		representation
            If textRepresentation(index) = 0 Then
                ReDim Preserve textRepresentation(textRepresentation.Length - 2)
                If boxIndex > 0 Then
                    boxIndex -= 1
                End If
                
                'update the index of the current letter
                charsIndex = textRepresentation(boxIndex)
            'Get out of the loop when a character is encountered
            Else
                index = -1
            End If
            
        Next
        HideCaret(TextBox1.Handle)
    End Sub

	'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The text has changed.
    'Post-Condition: The textbox has been updated.
    'Functionality: Create and update the caret so that they display correctly.
    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
        
        'When the text is changed, create the caret and show it
        CreateCaret(TextBox1.Handle, IntPtr.Zero, -7, FontHeight)
        ShowCaret(TextBox1.Handle)

        RaiseEvent textChanged(sender, e)
    End Sub

    'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: The visibility has changed.
    'Post-Condition: The caret is not shown if the control does not have focus.
    'Functionality: Ensure the caret is not shown when the control does not have focus.
    Private Sub visibilityChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.VisibleChanged

        If Me.Visible Then

            If Not Me.Focused Then
                HideCaret(TextBox1.Handle)
            End If

        End If

    End Sub
		
    'Overridden Functions
		
    'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: Some form of key down event has occured.
    'Post-Condition: The key down event has been trapped and handled.
    'Functionality: Trap keyboard keys and use the arrow keys and the enter key to
    '		create a text entry textbox that works with five keys.
    Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
        'Variable to hold the index of the start of the highlighted text
        Dim selectionStart As Integer
        
        'Variable to hold the length of the highlighted text
        Dim selectionLength As Integer

        If Not mouseReleased Then
        		
        		'If the key is the left arrow, move the mouse left
            If (keyData = Keys.Left) Or (keyData = Keys.NumPad4) Then
                keyMouseMove(-7, 0)
            
            'If the key is the right arrow, move the mouse right
            ElseIf (keyData = Keys.Right) Or (keyData = Keys.NumPad6) Then
                keyMouseMove(7, 0)
            
            'If the key is the down arrow, move the mouse down.
            ElseIf (keyData = Keys.Up) Or (keyData = Keys.NumPad8) Then
                keyMouseMove(0, -7)
            
            'If the key is the enter key, then click the mouse down
            ElseIf (keyData = Keys.Down) Or (keyData = Keys.NumPad2) Then
                keyMouseMove(0, 7)
            End If
            
        End If

				'If selection length is greater than 0, populate the selection variables
        If TextBox1.SelectionLength > 0 Then
            selectionStart = TextBox1.SelectionStart
            selectionLength = TextBox1.SelectionLength
        End If

				'If this function recieves a keydown event
        If (msg.Msg = WM_KEYDOWN) Or (msg.Msg = WM_SYSKEYDOWN) Then
        	
        		'If the key pressed is the up key, increase the index of the
        		'		character that the current caret position, commit
        		'		that change to internal representation, then update
        		'		the textbox
            If keyData = Keys.Up Or keyData = Keys.NumPad8 Then
                charsIndex = (charsIndex + 1) Mod MAX_CHARS_INDEX
                textRepresentation(boxIndex) = charsIndex
                arrayToBox()
            
            'If the key pressed is the down key, decreatese the index of the
            '		character at the current caret position, commit the change
            '		 to the internal representation, and update the textbox
            ElseIf keyData = Keys.Down Or keyData = Keys.NumPad2 Then
                charsIndex -= 1
                If charsIndex < 0 Then
                    charsIndex = MAX_CHARS_INDEX - 1
                End If
                textRepresentation(boxIndex) = charsIndex
                arrayToBox()
            
            'If the right arrow key is pressed
            ElseIf keyData = Keys.Right Or keyData = Keys.NumPad6 Then
            		
            		'If the enter key is not down
                If Not enterKeyDown Then
              			
              			'If there is no text selected
                    If TextBox1.SelectedText = "" Then
              					
              					'If the caret position is at the end of the internal
              					'		representation
                        If (boxIndex + 1) >= TextBox1.Text.Length Then
              
              							'If the textbox can fit more characters, then
              							'		increase the size of the internal representation
              							'		and start the position out as a space
                            If boxIndex < MAX_CHARS Then
                                ReDim Preserve textRepresentation(textRepresentation.Length)
                                boxIndex += 1
                                charsIndex = 0
                            'If the maximum number of characters has been
                            '		reached, then return true to signify that the
                            '		event has been handled.
                            Else
                                Return True
                            End If
                        
                        'If the caret postion is not at the end of the internal
                        '		representation, then increase the position of the
                        '		caret and get the index of the character at that position    
                        Else
                            boxIndex += 1
                            charsIndex = textRepresentation(boxIndex)
                        End If
                        
                    'If there is text selected, go to the right end of the
                    '		highlighted text and store the index of the character
                    Else
                        boxIndex = TextBox1.SelectionStart + TextBox1.SelectionLength - 1
                        charsIndex = textRepresentation(boxIndex)
                    End If
                    
                    'Update the textbox text via the internal representation
                    arrayToBox()
                    
                    'Make sure the caret is in view of the textbox
                    TextBox1.ScrollToCaret()
               
               	'If the enter Key is down, do highlighting
                Else
                    
                    'If there are characters to the right of the caret
                    If boxIndex < textRepresentation.Length - 1 Then
                        
                        'If no text has been highlighted yet, set the
                        '		highlightRight flag to true, hide the caret, updated
                        '		actually highlight the character, set the internal
                        '		position of the caret
                        If TextBox1.SelectedText = "" Then
                            highlightRight = True
                            HideCaret(TextBox1.Handle)
                            TextBox1.Select(boxIndex, 1)
                            boxIndex -= 1
                        'If text was highlighteed previously
                        Else
                        		'If the highlight right flag is true, then highlight
                        		'		the character to the right
                            If highlightRight Then
                                TextBox1.Select(TextBox1.SelectionStart, TextBox1.SelectionLength + 1)
                            'Otherwise, increase the position of the selection
                            '		start and decrease the selection length.  This
                            '		is for if the user was highlighting left, and
                            '		then "highlights right", it should unhighlight
                            '		the last character highlighted
                            Else
                                TextBox1.Select(TextBox1.SelectionStart + 1, TextBox1.SelectionLength - 1)
                            End If
                            
                        End If
                        
                        'Update the internal caret position
                        boxIndex += 1
                        
                        'get the index of the current character
                        charsIndex = textRepresentation(boxIndex)
                    End If
                    
                    'Make sure that the caret is visible in the textbox
                    TextBox1.ScrollToCaret()
                    
                    'Signifies that the event has been handled so that the event
                    '		will not bubble up
                    Return True
                End If
                
            'If the left arrow key is pressed
            ElseIf keyData = Keys.Left Or keyData = Keys.NumPad4 Then
                
                'If the enter key is not down
                If Not enterKeyDown Then
                
                		'If there is no selected text
                    If TextBox1.SelectedText = "" Then
                
                				'If there are characters to the left of the caret,
                				'		then hide the caret, update the internal
                				'		index of the caret, and get the index
                				'		of the current character
                        If boxIndex > 0 Then
                            arrowsPressedWithEnter = True
                            HideCaret(TextBox1.Handle)
                            boxIndex -= 1
                            charsIndex = textRepresentation(boxIndex)
                        End If
                    'If there is selected text, move the caret to the
                    '		beginning of the selection and get the index of the
                    '		current character
                    Else
                        boxIndex = TextBox1.SelectionStart
                        charsIndex = textRepresentation(boxIndex)
                    End If
                    
                    'Update the textbox text via the internal representation
                    arrayToBox()
                    
                    'Make sure that the caret is visible within the textbox
                    TextBox1.ScrollToCaret()
                'The enter key is down, do highlighting
                Else
                    
                    'If there are characters to the left of the caret
                    If boxIndex > 0 Then
                    
                    		'If no text has been selected yet, then set the
                    		'		highlight right flag to false, hide the caret, 
                    		'		select the character, and update the internal index
                    		'		of the caret
                        If TextBox1.SelectedText = "" Then
                            highlightRight = False
                            HideCaret(TextBox1.Handle)
                            TextBox1.Select(boxIndex, 1)
                            boxIndex += 1
                        'If text has already been selected
                        Else
                    				
                    				'If highlighting right, then decrease the selection
                    				'		length.  This is for when the user is
                    				'		highlighting to the right, and then presses the
                    				'		left arrow.  In this case, the last character
                    				'		highlighted should be un-highlighted
                            If highlightRight Then
                                TextBox1.Select(TextBox1.SelectionStart, TextBox1.SelectionLength - 1)
                            'Otherwise, highlight the character to the left
                            Else
                                TextBox1.Select(TextBox1.SelectionStart - 1, TextBox1.SelectionLength + 1)
                            End If
                            
                        End If
                        
                        'Update the internal index of the caret position
                        boxIndex -= 1
                        
                        'Get the index of the current character
                        charsIndex = textRepresentation(boxIndex)
                        
                    End If
                    
                    'Make sure the caret is in view within the textbox
                    TextBox1.ScrollToCaret()
                    
                    'Return true tells the system that the event has been
                    '		handled so that the event does not bubble up
                    Return True
                    
                End If
            
            'If the enter key is pressed
            ElseIf keyData = Keys.Enter Or keyData = Keys.NumPad5 Then
            
            		'Set the flag that the enter key is down
                enterKeyDown = True
                
                'If the enter key is down, and arrowsPressedWithEnter
                '		is true, then set arrowsPressedWithEnter to false
                If enterKeyDown And arrowsPressedWithEnter Then
                    arrowsPressedWithEnter = False
                'If arrowsPressedWithEnter is false, then open the context menu
                '		if it is not already visible
                Else
            
                    If Not ContextMenuStrip1.Visible Then
                        ContextMenuStrip1.Show(TextBox1, TextBox1.Location.X + TextBox1.Width, TextBox1.Location.Y)
                    End If
                    
                End If
                
            End If
            
        End If
        
        'Returning true keeps the event from bubbling up.
				'This means that the system is informed that the
				'event has been handled.
        Return True
    End Function

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: Some form of key event has occured.
		'Post-Condition: return true so the event does not bubble up.
		'Functionality: Stop the system from handling keydown events.
    Protected Overrides Function ProcessDialogKey(ByVal keyData As System.Windows.Forms.Keys) As Boolean
        'Returning true keeps the event from bubbling up.
				'This means that the system is informed that the
				'event has been handled.
        Return True
    End Function

		'Developer Name: Jason Lyle
    'Module Name: Textbox Control
    'Task(s): N/A
    'Pre-Condition: Some form of key up event has occured.
    'Post-Condition: The key up event has been trapped and handled appropriately.
    'Functionality: Thrap keyboard keys up event to simulate a mouse.
    Protected Overrides Function ProcessKeyPreview(ByRef m As System.Windows.Forms.Message) As Boolean
        
        'If a keyup event occurs...
        If m.Msg = WM_KEYUP Or m.Msg = WM_SYSKEYUP Then
            
            'If the keyup is the enter key
            If (m.WParam = Keys.Enter) Or (m.WParam = Keys.NumPad5) Then

								'Set the flag representing the mouse state
                If Not mouseReleased Then
                    mouseReleased = True
                End If

								'Set the flag representing the enter key state
                enterKeyDown = False
                
                'Returning true keeps the event from bubbling up.
								'This means that the system is informed that the
								'event has been handled.
                Return True
            End If
            
        'If the event is not a keup event, let the event bubble up
        Else
            Return MyBase.ProcessKeyPreview(m)
        End If
        
    End Function
		
		'Other Functions
		
		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: None
		'Post-Condition: A left mouse button up event is in the clickstream.
		'Functionality: Place a left mouse button up event in the clistream.
    Public Sub keyMouseUp()

				'Create an intput type object
		    Dim inputEvents(0) As INPUT_TYPE
		
				'Set the members for a left mouse button up event.
		    inputEvents(0).xi.dx = 0
		    inputEvents(0).xi.dy = 0
		    inputEvents(0).xi.mouseData = 0
		    inputEvents(0).xi.dwFlags = MOUSE_LEFTUP
		    inputEvents(0).xi.dwtime = 0
		    inputEvents(0).xi.dwExtraInfo = 0
		    inputEvents(0).dwType = INPUT_MOUSE
		
				'Insert the event into the clickstream
		    SendInput(1, inputEvents(0), Len(inputEvents(0)))
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: None
		'Post-Condition: A mouse movement by x and y pixels is inserted to the
		'		clickstream.
		'Functionality: Move the mouse by x and y pixels.
    Public Sub keyMouseMove(ByVal x As Integer, ByVal y As Integer)
		
				'Create an intput type object
		    Dim inputEvents(0) As INPUT_TYPE
		
				'Set the members for a left mouse movement event.
		    inputEvents(0).xi.dx = x
		    inputEvents(0).xi.dy = y
		    inputEvents(0).xi.mouseData = 0
		    inputEvents(0).xi.dwFlags = MOUSE_MOVE
		    inputEvents(0).xi.dwtime = 0
		    inputEvents(0).xi.dwExtraInfo = 0
		    inputEvents(0).dwType = INPUT_MOUSE
		    
				'Insert the event into the clickstream
		    SendInput(1, inputEvents(0), Len(inputEvents(0)))
    End Sub
		
		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: the color of the texbox has changed.
		'Post-Condition: An event is raised signaling the color change.
		'Functionality: Raise a color change event.
    Private Sub raiseColorChangeEvent(ByVal newColor As Color)
        
        'Raise the event representing that the color of the text was changed
        RaiseEvent colorChanged(Me, newColor)
    End Sub
    
    'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: There is text in the textbox that is not represented in the
		'		internal representation, textRepresentation
		'Post-Condition: The internal representation now represents everything in
		'		the textbox.
		'Functionality: Load what is in the textbox into the internal representation
    Public Sub BoxToArray()
    
    		'An integer prepresenting the length of the text in the textbox
        Dim txtLength As Integer

				'If the textbox is not empty
        If Not TextBox1.Text = "" Then
        		
        		'Get the length of the text
            txtLength = TextBox1.Text.Length - 1
            
            'Change all the text to lower case
            TextBox1.Text = TextBox1.Text.ToLower
            
            'Change the length of the internal representation
            ReDim textRepresentation(txtLength)
            
            'set the cursor position to the beginning
            boxIndex = 0
            
            'go through each character in the text box
            For index1 As Integer = 0 To txtLength
                
                'For each character in the textbox, look through
                'all the characters in the textRepresentation array
                'to find a match.  If no math is found, then the 
                'character location is left as a space.
                For index2 As Integer = 0 To MAX_CHARS_INDEX - 1
                    
                    If TextBox1.Text(index1) = chars(index2) Then
                        textRepresentation(index1) = index2
                    End If
                    
                Next
                
            Next
            
            'Set the index to the loaded length
            boxIndex = txtLength
            
            'Ensure everything is loaded correctly
            'and properly initialized
            arrayToBox()
        End If
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: None
		'Post-Condition: The internal representation is displayed in the textbox
		'Functionality: Display the internal representation of the textbox.
    Private Sub arrayToBox()
    
    		'Get the length of the text representation array
        Dim arrayLength As Integer = textRepresentation.Length

				'set the first character in the textbox to the first character in the
				'		internal representation
        TextBox1.Text = chars(textRepresentation(0))
        
        'For every character in the internal representation, place it into the
        '		textbox
        For counter As Integer = 1 To arrayLength - 1
            TextBox1.Text = TextBox1.Text + chars(textRepresentation(counter))
        Next
        
        'Move the caret to the end of the text in the textbox
        TextBox1.Select(boxIndex + 1, 0)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: None
		'Post-Condition: The textbox is cleared of text.
		'Functionality: Clear the textbox.
    Public Sub Clear()
    
        'Clear the internal representation
        ReDim textRepresentation(0)

        'Update the state variables
        boxIndex = 0
        charsIndex = textRepresentation(boxIndex)

        'Update the screen representation
        arrayToBox()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: There is text in the textbox.
		'Post-Condition: All the text in the textbox is highlighted.
		'Functionality: Highlight all the text in the textbox.
    Public Sub SelectAll()
        TextBox1.SelectAll()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): Every Cut task.  I don't want to list them and you dont want me
		'		to list them all either.
		'Pre-Condition: There is text in the textbox that is highlighted.
		'Post-Condition: The text that was highlighted is removed from the textbox
		'		and placed onto the system's clipboard.
		'Functionality: Cut the highlighted text.
    Public Sub Cut()
    		
    		'Send a message that text must be highlighted in order to cut if no text
    		'		is highlighted
        If (TextBox1.SelectedText = "") Then
            MsgBox("Please select text to cut.", MsgBoxStyle.Exclamation)
        'Otherwise, copy the highlighted text (in all lowercase) to the
        '		clipboard, and then delete the highlighted text
        Else
            My.Computer.Clipboard.SetText(TextBox1.SelectedText.ToLower)
            DeleteHighlightedText()
        End If
        
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): Every Copy task.  I don't want to list them and you dont want me
		'		to list them all either.
		'Pre-Condition: There is text in the textbox that is highlighted.
		'Post-Condition: The text that was highlighted is placed onto the system's
		'		clipboard.
		'Functionality:   Copy the highlighted text.
    Public Sub Copy()
    
    		'Send a message that text must be highlighted in order to copy, if no text
    		'		is highlighted
        If (TextBox1.SelectedText = "") Then
            MsgBox("Please select text to copy.", MsgBoxStyle.Exclamation)
        'Otherwise, place the highlighted text on the clipboard
        Else
            My.Computer.Clipboard.SetText(TextBox1.SelectedText.ToLower)
        End If
        
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): Every paste task,  I don't want to list them and you dont want me
		'		to list them all either.
		'Pre-Condition: There is text on the system's clipboard
		'Post-Condition: The text on the system's clipboard is in the textbox.
		'Functionality: Paste the system's clipboard's text.
    Public Sub Paste()
    		
    		'Get the text from the clipboard to paste (in all lowercase)
        Dim pasteText As String = My.Computer.Clipboard.GetText.ToLower
        
        'Get the length of the text to be pasted
        Dim pasteTextLength As Integer = pasteText.Length - 1
        
        'Get the position where the text is to be pasted
        Dim startIndex As Integer = TextBox1.SelectionStart - 1
        
        'Get how many characters are highlighted
        Dim selectLength As Integer = TextBox1.SelectionLength
        
        'Get the length of the text that is is going to be positioned after
        '		 the pasted text
        Dim endingTextLength As Integer = textRepresentation.Length - 1 - (startIndex + selectLength)
        
        If endingTextLength < 0 Then
            endingTextLength = 0
        End If

				'Set up an array that will internally represent the text that comes
				'		after the pasted text
        Dim counter As Integer = 0
        Dim EndingText(endingTextLength) As Integer

        For index As Integer = startIndex + selectLength To textRepresentation.Length - 1
            EndingText(counter) = textRepresentation(index)
            counter += 1
        Next

				'Change the size of the internal representation array to fit the new
				'		text from the paste
        ReDim Preserve textRepresentation(startIndex + pasteTextLength + counter)

        counter = startIndex
      	'Loop through all the characters in the representation of the pasted
      	'		text
        For index1 As Integer = 0 To pasteTextLength
            
            'Loop throguh all the characters in the array of possible characters
            For index2 As Integer = 0 To MAX_CHARS_INDEX - 1
            
            		'If the character in the pasted text matches the character in
            		'		the array of possible letter, add it to the internal
            		'		representation array
            		'NOTE: VB arrays auto populate cells without values with 0's
            		'		which is a space in the array of possible characters.
            		'		Because of this, if an invalid character is pasted
            		'		into the textbox, it will show up as a space
                If pasteText(index1) = chars(index2) Then
                    textRepresentation(counter) = index2
                End If
                
            Next
            
            counter += 1
            
        Next

        counter = 0
        
        'Add the ending text back into the internal representation
        For index As Integer = startIndex + pasteTextLength + 1 To textRepresentation.Length - 1
            textRepresentation(index) = EndingText(counter)
            counter += 1
        Next

				'Move the internal representation into the textbox
        arrayToBox()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: There is text that is highlighted
		'Post-Condition: The highligted text is deleted
		'Functionality: Delete the hightlighted text.
    Public Sub DeleteHighlightedText()
    
    		'Get the start index of the highlighted text
        Dim startIndex As Integer = TextBox1.SelectionStart
        
        'get the length of the highligted text
        Dim selectLength As Integer = TextBox1.SelectionLength
        
        'Get the length of the text that comes after the highlighted text
        Dim endingTextLength As Integer = textRepresentation.Length - 1 - (startIndex + selectLength)
        
        Dim counter As Integer = 0
        
        'Create an internal representation array for the text that comes after
        '		the highlighted text
        Dim endingText(endingTextLength) As Integer

        'If everything is selected, just clear the textbox
        If selectLength = textRepresentation.Length Then
            Clear()
            Return
        End If

				'Populate the array that holds the internal representation of the text
				'		that comes after the highlighted text
        For index As Integer = startIndex + selectLength To textRepresentation.Length - 1
            endingText(counter) = textRepresentation(index)
            counter += 1
        Next

				'Change the size of the internal represenation array
        ReDim Preserve textRepresentation(textRepresentation.Length - 1 - selectLength)
        
        counter = startIndex
        
        'Move the ending text into the place of the highlighted text
        For index As Integer = 0 To endingText.Length - 1
            textRepresentation(counter) = endingText(index)
            counter += 1
        Next
        boxIndex -= 1

				'Ensure the caret position is not too small or too big
        If boxIndex < 0 Then
            boxIndex = 0
        ElseIf boxIndex > textRepresentation.Length - 1 Then
            boxIndex = textRepresentation.Length - 1
        End If

				'Get the index of the current character
        charsIndex = textRepresentation(boxIndex)
        
        'Update the textbox via the internal representation
        arrayToBox()
    End Sub
		
		'Context Menu Functions
		
		'First Level Menu
		
		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu for the textbox was previous closed.
		'Post-Condition: The context menu for the textbox is open and the options
		'		are set to the appropriate states.
		'Functionality: Set the states of the options of the context menu (enabled
		'		or not).
    Private Sub ContextMenuStrip1_Opening(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStrip1.Opening
        
        'If there is no text on the clipboard, disable the paste option
        If Not My.Computer.Clipboard.ContainsText() Then
            PasteToolStripMenuItem.Enabled = False
        'Otherwise, enable the paste option
        Else
            PasteToolStripMenuItem.Enabled = True
        End If


				'If no text is highlighted, disable the copy, cut, and delete selection
				'		options
        If TextBox1.SelectedText = "" Then
            CopyToolStripMenuItem.Enabled = False
            CutToolStripMenuItem.Enabled = False
            DeleteSelectionToolStripMenuItem.Enabled = False
        'Otherwise, enable  the copy, cut, and delete selection options
        Else
            CopyToolStripMenuItem.Enabled = True
            CutToolStripMenuItem.Enabled = True
            DeleteSelectionToolStripMenuItem.Enabled = True
        End If

				'If everything is selected, disable the select all option
        If TextBox1.SelectionLength = TextBox1.TextLength Then
            SelectAllToolStripMenuItem.Enabled = False
        'Otherwise, enable the select all option
        Else
            SelectAllToolStripMenuItem.Enabled = True
        End If

    End Sub
		
		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): All the cut tasks, I dont want to list them and you dont want me
		'		to list them all either.
		'Pre-Condition: Text is selected in the textbox.
		'Post-Condition: The selected text is removed from the textbox and placed
		'		 on the system's clipboard.
		'Functionality: Cut the highlighted text.
    Private Sub CutToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CutToolStripMenuItem.Click
        Cut()
    End Sub
		
		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): Every copy task,  I dont want to list them and you dont want me
		'		to list them all either.
		'Pre-Condition: Text is hightlighted.
		'Post-Condition: The highlighted text is on the system's clipboard.
		'Functionality: Copy the highlighted text.
    Private Sub CopyToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CopyToolStripMenuItem.Click
        Copy()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): Every paste task, I dont want to list them and you dont want me
		'		to list them all either.
		'Pre-Condition: There is text on the system's clipboard.
		'Post-Condition: The text on the system's clipboard is now in the textbox.
		'Functionality: Paste text into the textbox.
    Private Sub PasteToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PasteToolStripMenuItem.Click
        Paste()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: There is text in the textbox.
		'Post-Condition: The text in the textbox is highlighted.
		'Functionality: Highlight all the text in the textbox.
    Private Sub SelectAllToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SelectAllToolStripMenuItem.Click
        SelectAll()
        
        'Hide the caret when any text is selected
        HideCaret(TextBox1.Handle)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: Text is selected.
		'Post-Condition: The text that was selected is removed from th textbox.
		'Functionality: Delete the selected text.
    Private Sub DeleteSelectionToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DeleteSelectionToolStripMenuItem.Click
        DeleteHighlightedText()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: There is text in the textbox.
		'Post-Condition: There is no text in the textbox.
		'Functionality: Clear the textbox.
    Private Sub ClearToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearToolStripMenuItem.Click
        Clear()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: Context menu is open.
		'Post-Condition: The context menu is closed.
		'Functionality: Close the context menu.
    Private Sub CancelToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CancelToolStripMenuItem.Click
        ContextMenuStrip1.Close()
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: 
		'Post-Condition: 
		'Functionality: 
    Private Sub LeaveTextboxToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LeaveTextboxToolStripMenuItem.Click
        
        'Try to switch focus to the switchTo, but if the user has not set this
        '		porperty, a NullReferenceException will occur.  The try, catch 
        '		block stops this from crashing the system, and the focus
        '		remains on the textbox.
        Try
            switchTo.Focus()
        Catch exc As NullReferenceException
        End Try
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu is open
		'Post-Condition: The color of the text is blue.
		'Functionality: Change the text color to blue.
    Public Sub BlueToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BlueToolStripMenuItem.Click
        TextBox1.ForeColor = Color.Blue
        raiseColorChangeEvent(Color.Blue)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu is open
		'Post-Condition: The color of the text is Red.
		'Functionality: Change the text color to Red.
    Public Sub RedToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RedToolStripMenuItem.Click
        TextBox1.ForeColor = Color.Red
        raiseColorChangeEvent(Color.Red)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu is open
		'Post-Condition: The color of the text is Yellow.
		'Functionality: Change the text color to Yellow.
    Public Sub YellowToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles YellowToolStripMenuItem.Click
        TextBox1.ForeColor = Color.Yellow
        raiseColorChangeEvent(Color.Yellow)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu is open
		'Post-Condition: The color of the text is Black.
		'Functionality: Change the text color to Black.
    Public Sub BlackToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BlackToolStripMenuItem.Click
        TextBox1.ForeColor = Color.Black
        raiseColorChangeEvent(Color.Black)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu is open
		'Post-Condition: The color of the text is Magenta.
		'Functionality: Change the text color to Magenta.
    Public Sub MagentaToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MagentaToolStripMenuItem.Click
        TextBox1.ForeColor = Color.Magenta
        raiseColorChangeEvent(Color.Magenta)
    End Sub

		'Developer Name: Jason Lyle
		'Module Name: Textbox Control
		'Task(s): N/A
		'Pre-Condition: The context menu is open
		'Post-Condition: The color of the text is Green.
		'Functionality: Change the text color to Green.
    Public Sub GreenToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GreenToolStripMenuItem.Click
        TextBox1.ForeColor = Color.Green
        raiseColorChangeEvent(Color.Green)
    End Sub
End Class